package org.tinygame.herostory.codec;

import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.Message;
import org.tinygame.herostory.msg.GameMsgProtocol;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 消息识别器
 */
public final class GameMsgCoder {

    private GameMsgCoder(){}

    //消息代码和消息体字典
    private final static Map<Integer, GeneratedMessageV3> msgCodeAndMsgBodyMap = new ConcurrentHashMap<>();
    //消息类型和消息编号字典
    private final static Map<Class<?>, Integer> msgClazzAndMsgCodeMap = new ConcurrentHashMap<>();

    //动态初始化 - 反射动态获取
    public static void init(){
        Class<?>[] innerClazzArray = GameMsgProtocol.class.getDeclaredClasses();

        for (Class<?> innerClazz : innerClazzArray){
            if(!GeneratedMessageV3.class.isAssignableFrom(innerClazz)){
                continue;
            }
            String className = innerClazz.getSimpleName();
            className = className.toLowerCase();

            for (GameMsgProtocol.MsgCode msgCode : GameMsgProtocol.MsgCode.values()){
                String msgCodeStr = msgCode.name();
                msgCodeStr = msgCodeStr.replaceAll("_","");
                msgCodeStr = msgCodeStr.toLowerCase();

                if(!msgCodeStr.equals(className)){
                    continue;
                }

                try {
                    Object returnObj = innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);
                    msgCodeAndMsgBodyMap.put(msgCode.getNumber(),(GeneratedMessageV3) returnObj);
                    msgClazzAndMsgCodeMap.put(innerClazz,msgCode.getNumber());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 解码识别
     * @param msgCode
     * @return
     */
    public static Message.Builder getBuilderByMsgCode(int msgCode){

        if(msgCode < 0){
            return null;
        }

        GeneratedMessageV3 msg = msgCodeAndMsgBodyMap.get(msgCode);

        if(null == msg){
            return null;
        }

        return msg.newBuilderForType();
    }

    /**
     * 编码识别
     * @param msgClazz
     * @return
     */
    public static int getMsgCodeByMsgClazz(Class<?> msgClazz){

        if(null == msgClazz){
            System.out.println("无法识别的消息类型：" + msgClazz);
            return -1;
        }

        Integer msgCode = msgClazzAndMsgCodeMap.get(msgClazz);

        if(null == msgCode){
            System.out.println("无法识别的消息类型：" + msgClazz);
            return -1;
        } else {
            return msgCode.intValue();
        }

    }

}
